﻿// <copyright file="Puzzle.cs" company="ThorIndustry">Copyright (c) ThorIndustry. All rights reserved.</copyright>

public class Puzzle
{
    public PuzzleDefinition Definition
    {
        get;
        private set;
    }

    public PuzzleShape[] Shapes
    {
        get;
        private set;
    }

    public PuzzleSolutionShape PuzzleSolutionShape
    {
        get;
        private set;
    }

    public bool CheckAgainstSolution()
    {
        ////// Is all the shape in the solution shape?
        ////for (int index = 0; index < this.Shapes.Length; ++index)
        ////{
        ////    for (int vertice = 0; vertice < this.Shapes[index].Vertices.Length; ++vertice)
        ////    {
        ////        if (!this.SolutionShape.IsPointInShape(this.Shapes[index].WorldVertices[vertice]))
        ////        {
        ////            return false;
        ////        }
        ////    }
        ////}

        ////// Is any shape overlapping another one?
        // Try a brut force algorithm.
        // The puzzle is valid when all vertice in the shape are either:
        // -> Overlapping at least one other shape vertice.
        // -> Overlapping a solution vertice.
        for (int shapeIndex = 0; shapeIndex < this.Shapes.Length; ++shapeIndex)
        {
            if (!this.HasAllVerticeCovered(this.Shapes[shapeIndex], true))
            {
                return false;
            }
        }

        return this.HasAllVerticeCovered(this.PuzzleSolutionShape, false);
    }

    private bool HasAllVerticeCovered(IWorldVerticeProvider shape, bool testSolution)
    {
        bool verticeCovered = false;
        for (int index = 0; index < shape.WorldVertices.Length; ++index)
        {
            verticeCovered = false;
            for (int shapeIndex = 0; shapeIndex < this.Shapes.Length; ++shapeIndex)
            {
				if (this.Shapes[shapeIndex] == shape)
				{
					continue;
				}

                if (this.HasAnotherVerticeAtPosition(this.Shapes[shapeIndex], shape.WorldVertices[index]))
                {
                    verticeCovered = true;
                    break;
                }
            }

            if (!verticeCovered &&
			    testSolution &&
                !this.HasAnotherVerticeAtPosition(this.PuzzleSolutionShape, shape.WorldVertices[index]))
            {
                return false;
            }
        }
        
        return true;
    }

    private bool HasAnotherVerticeAtPosition(IWorldVerticeProvider shape, UnityEngine.Vector3 worldPosition)
    {
        for (int index = 0; index < shape.WorldVertices.Length; ++index)
        {
            if (UnityEngine.Mathf.Abs(shape.WorldVertices[index].x - worldPosition.x) < 0.1f &&
			    UnityEngine.Mathf.Abs(shape.WorldVertices[index].y - worldPosition.y) < 0.1f)
            {
                return true;
            }
        }

        return false;
    }

    public void Initialize(PuzzleDefinition definition)
    {
        this.Definition = definition;

        // Get the several puzzle definition and create the shape.
        IPuzzleService puzzleService = Services.GetService<IPuzzleService>();
        this.Shapes = puzzleService.GetPuzzleShapesByPuzzleShapeDefinitionName(this.Definition.ShapesDefinitionName);

        // Get the solution definition and create the shape.
        this.PuzzleSolutionShape = new PuzzleSolutionShape(this.Definition.Solution);
        this.PuzzleSolutionShape.Initialize();

        bool hasOutline = this.Definition.Outline != null &&
                          this.Definition.Outline.ShapePosition != null &&
                          this.Definition.Outline.ShapePosition.Length == this.Shapes.Length;

        int halfSize = this.Shapes.Length / 2;
        for (int index = 0; index < this.Shapes.Length; ++index)
        {
            if (hasOutline)
            {
                // Place the shapes...
                this.Shapes[index].ChangePosition(this.Definition.Outline.ShapePosition[index]);
            }
            else
            {
                this.Shapes[index].ChangePosition(new UnityEngine.Vector3((halfSize - index) * 6, (halfSize - index) * 6, 0), 0, false);
            }
        }
    }
}

